package main;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Vector;

import tree.Tree;
import utils.Stopwatch;
import utils.Utils;
import gp.GeneticProgram;

public final class Main {
	
	private static final int ELITISM = 2;
	private static final int POPULATION_SIZE = 300;
	
	//employ elitism only for trees with fitness below this value
	private static final double MAX_FITNESS_FOR_ELITISM = 20000;
	
	//maximum depth for random trees (recombinated trees may be deeper...)
	private static final int MAX_DEPTH = 6;
	
	private static final int MIN_NUM_NODES_PENALTY = 10;
	
	private static final double MUTATION_PROBABILITY = 0.1;
	
	//number of random trees to introduce in each new generation
	private static final int NUM_RANDOM_TREES_PER_GEN = 4;
		
	private static final int NUM_TREES_PER_TOURNAMENT_SELECTION = 10;
	
	private static final int NUM_OF_EXAMPLES = 30;
	
	private static final double TIME_IN_SECONDS = 60.0;
	
	private static String FILENAME = "data3";
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		GeneticProgram gp = new GeneticProgram(POPULATION_SIZE, MAX_DEPTH, MUTATION_PROBABILITY, ELITISM, 
				MAX_FITNESS_FOR_ELITISM, NUM_RANDOM_TREES_PER_GEN, NUM_TREES_PER_TOURNAMENT_SELECTION,
				MIN_NUM_NODES_PENALTY);
				
		Vector<double[]> allVals = readExamples();

		Stopwatch stopwatch = new Stopwatch();
		
		PrintStream outStream = null;
		try {
			outStream = new PrintStream(new File("equation.txt"));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		int j = 0;
		while(stopwatch.elapsedTime() < TIME_IN_SECONDS)
		{
			//System.out.print("\"" +  j + "\",");
			try {
				
				Vector vals = getPartOfExamples(allVals);
				gp.TrainNextGeneration(vals, outStream, false);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			j++;
		}
		
		try {
			//System.out.println("---- Final: -----");
			gp.TrainNextGeneration(allVals, outStream, true);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		outStream.close();
	}
	
	private static Vector getPartOfExamples(Vector<double[]> allVals) {
		Vector<double[]> result = new Vector<double[]>();
		for(int i = 0; i < NUM_OF_EXAMPLES; i++)
		{
			result.add(allVals.get(Utils.rand.nextInt(allVals.size())));
		}
		
		return result;
	}

	private static Vector<double[]> readExamples()
	{
		Vector<double[]> result = new Vector<double[]>();
		try
		{
			FileInputStream fstream = new FileInputStream(FILENAME + ".txt");
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			
			String strLine;
			boolean firstLine = true;
			while ((strLine = br.readLine()) != null)   {
				if(firstLine)
				{
					firstLine = false;
				}
				else
				{
					String[] args = strLine.split(",");
					
					result.add(new double[] { Double.parseDouble(args[0]), Double.parseDouble(args[1]) });
				}
			}
			
			in.close();
		} 
		catch (Exception e)
		{
			System.err.println("Error: " + e.getMessage());
		}
		
		return result;
	}
}
